﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using Finance.Controllers;
using Finance.Data.Entities;
using Finance.GUI.ViewModels;

namespace Finance.ViewModels
{
	internal class DocumentViewModel : DocumentViewModelBase
	{
		private readonly IDocumentController _controller;
		private const int MaxSearchResultCount = 6;

		private string _searchProductString;
		public BindingList<DocumentProductViewModel> Products { get; private set; }
        
		public DocumentViewModel(
			IDocumentBase document, 
			IDocumentController controller)
			:base(document, controller)
		{
			_controller = controller;
			Products = new BindingList<DocumentProductViewModel>();
			ProductsSearchResult = new BindingList<ProductSearchResult>();

			Products.ListChanged += OnProductsListChanged;

			var doc = document as IDocument;
			if (doc != null)
			{
				foreach (var documentProductView in 
					doc.Products.Select(documentProduct => new DocumentProductViewModel(documentProduct)))
				{
					Products.Add(documentProductView);
				}
				HasProductList = true;
			}
			else
			{
				HasProductList = false;
			}
		}

		public bool HasProductList { get; set; }

		public BindingList<ProductSearchResult> ProductsSearchResult { get; private set; }

		public string SearchProductString
		{
			get { return _searchProductString; }
			set
			{
				if (_searchProductString == value)
					return;
				
				_searchProductString = value;

				UpdateProductSearchResult(value);
			}
		}

		private void UpdateProductSearchResult(string value)
		{
			ProductsSearchResult.Clear();

			//Too short
			if (_searchProductString.Length < 2)
				return;

			ProductsSearchResult.RaiseListChangedEvents = false;

			_controller.GetProductsWithPrices(
				ProductsSearchResult, 
				value, 
				MaxSearchResultCount, 
				Contractor == null? Guid.Empty : Contractor.Id,
				Document.DocDate);
            
			ProductsSearchResult.RaiseListChangedEvents = true;

			if(ProductsSearchResult.Count > 0)
				ProductsSearchResult.Insert(0, new ProductSearchResult { Name = _searchProductString });
		}

		void OnProductsListChanged(object sender, ListChangedEventArgs e)
		{
			if (e.ListChangedType == ListChangedType.ItemAdded)
			{
				var documentProductView = Products[e.NewIndex];
				documentProductView.PropertyChanged += OnProductViewPropertyChanged;
			}
		}

		void OnProductViewPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "TotalPrice" && _autoCalculateDocumentTotalAmount)
			{
				SetAmount(Products.Sum(p => p.TotalPrice).ToString(CultureInfo.InvariantCulture));
			}
		}

		public override void ApplyChangesToModel()
		{
			base.ApplyChangesToModel();
			
			foreach (var documentProductView in Products)
			{
				documentProductView.ApplyChanges();
			}

			var doc = Document as IDocument;
			if (doc != null)
			{
				//new rows
				foreach (var documentProductView in Products.Where(documentProduct => documentProduct.DocumentProduct == null))
				{
					var documentProduct = doc.NewProduct();
					documentProductView.AttachDocumentProduct(documentProduct);
					doc.Products.Add(documentProduct);
				}
				var removedList = doc.Products.Where(dp => Products.All(v => v.DocumentProduct != dp)).ToList();
				foreach (var removedProduct in removedList)
				{
					doc.Products.Remove(removedProduct);
				}
			}
		}

		public void NewProduct()
		{
			Products.Add(new DocumentProductViewModel(null));
		}

		public void RemoveProductAt(int indexToRemove)
		{
			var productView = Products[indexToRemove];
			productView.PropertyChanged -= OnProductViewPropertyChanged;
			Products.Remove(productView);
		}
	}

	public class ProductSearchResult
	{
		public Guid ProductId;
		public string Name { get; set; }
		public decimal Price;

		public override string ToString()
		{
			if (Price == 0)
				return Name;

			return Name + " - " + Price.ToString(CultureInfo.InvariantCulture);
		}
	}
}
